package com.hwapitest.utils;

import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public class HttpRequestJsonUtil {
    private static Logger logger = Logger.getLogger(HttpRequestJsonUtil.class);

    // 连接池管理器（全局唯一）
    private static final PoolingHttpClientConnectionManager connManager;

    // 共享的HTTP客户端（支持连接池）
    private static final CloseableHttpClient httpClient;

    // 重试处理器
    private static final HttpRequestRetryHandler retryHandler;

    // 超时配置
    private static final RequestConfig requestConfig;

    static {
        // 初始化连接池
        connManager = new PoolingHttpClientConnectionManager();
        connManager.setMaxTotal(200);          // 最大连接数
        connManager.setDefaultMaxPerRoute(50); // 每个路由最大连接数

        // 配置重试策略
        retryHandler = (exception, executionCount, context) -> {
            if (executionCount >= 3) { // 最多重试3次
                return false;
            }
            if (exception instanceof InterruptedIOException) {
                // 超时不重试
                return false;
            }
            if (exception instanceof ConnectTimeoutException) {
                // 连接超时重试
                return true;
            }
            // 其他情况重试
            return true;
        };

        // 配置超时参数
        requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)    // 连接超时 5秒
                .setSocketTimeout(15000)     // 读取超时 15秒
                .setConnectionRequestTimeout(3000) // 请求超时 3秒
                .build();

        // 创建带连接池的HttpClient
        httpClient = HttpClients.custom()
                .setConnectionManager(connManager)
                .setRetryHandler(retryHandler)
                .setDefaultRequestConfig(requestConfig)
                .evictIdleConnections(30, TimeUnit.SECONDS) // 空闲连接超时
                .build();

        // 添加JVM关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                httpClient.close();
                connManager.close();
            } catch (IOException e) {
                logger.error("关闭HTTP客户端失败", e);
            }
        }));
    }

    /**
     * 发送JSON请求
     *
     * @param url         请求URL
     * @param requestType 请求类型 (GET, POST, PUT, PATCH, DELETE)
     * @param jsonObject  请求体JSON对象
     * @param headers     请求头JSON对象
     * @return 响应内容字符串
     */
    public static String sendRequest(String url, String requestType,
                                     JSONObject jsonObject, JSONObject headers) {
        HttpRequestBase request = createRequest(url, requestType, jsonObject);

        // 添加请求头
        addHeaders(request, headers);

        // 执行请求
        return executeRequest(request);
    }

    // ==================== 私有方法 ====================

    /**
     * 创建HTTP请求对象
     */
    private static HttpRequestBase createRequest(String url, String requestType,
                                                 JSONObject jsonObject) {
        requestType = requestType.toUpperCase();

        switch (requestType) {
            case "POST":
                return createPostRequest(url, jsonObject);
            case "PUT":
                return createPutRequest(url, jsonObject);
            case "PATCH":
                return createPatchRequest(url, jsonObject);
            case "DELETE":
                return createDeleteRequest(url, jsonObject);
            case "GET":
                return createGetRequest(url, jsonObject);
            default:
                throw new IllegalArgumentException("不支持的请求类型: " + requestType);
        }
    }

    /**
     * 创建POST请求
     */
    private static HttpPost createPostRequest(String url, JSONObject jsonObject) {
        HttpPost post = new HttpPost(url);
        setJsonEntity(post, jsonObject);
        return post;
    }

    /**
     * 创建PUT请求
     */
    private static HttpPut createPutRequest(String url, JSONObject jsonObject) {
        HttpPut put = new HttpPut(url);
        setJsonEntity(put, jsonObject);
        return put;
    }

    /**
     * 创建PATCH请求
     */
    private static HttpPatch createPatchRequest(String url, JSONObject jsonObject) {
        HttpPatch patch = new HttpPatch(url);
        setJsonEntity(patch, jsonObject);
        return patch;
    }

    /**
     * 创建DELETE请求
     */
    private static HttpDeleteWithBody createDeleteRequest(String url, JSONObject jsonObject) {
        HttpDeleteWithBody delete = new HttpDeleteWithBody(url);
        setJsonEntity(delete, jsonObject);
        return delete;
    }

    /**
     * 创建GET请求（将JSON参数转为URL参数）
     */
    private static HttpGet createGetRequest(String url, JSONObject jsonObject) {
        StringBuilder urlBuilder = new StringBuilder(url);

        if (jsonObject != null && !jsonObject.isEmpty()) {
            urlBuilder.append("?");
            Set<String> keys = jsonObject.keySet();
            for (String key : keys) {
                String value = jsonObject.getString(key);
                urlBuilder.append(key)
                        .append("=")
                        .append(value)
                        .append("&");
            }
            // 删除最后一个'&'
            urlBuilder.setLength(urlBuilder.length() - 1);
        }

        return new HttpGet(urlBuilder.toString());
    }

    /**
     * 设置JSON请求体
     */
    private static void setJsonEntity(HttpEntityEnclosingRequestBase request, JSONObject jsonObject) {
        if (jsonObject == null || jsonObject.isEmpty()) {
            return;
        }

        try {
            StringEntity entity = new StringEntity(
                    jsonObject.toString(),
                    StandardCharsets.UTF_8
            );
            request.setEntity(entity);
        } catch (Exception e) {
            logger.error("创建请求体失败", e);
            throw new RuntimeException("创建请求体失败", e);
        }
    }

    /**
     * 添加请求头
     */
    private static void addHeaders(HttpRequestBase request, JSONObject headers) {
        if (headers == null || headers.isEmpty()) {
            // 设置默认Content-Type
            if (request instanceof HttpEntityEnclosingRequestBase) {
                request.addHeader("Content-Type", "application/json; charset=utf-8");
            }
            return;
        }

        Set<String> keys = headers.keySet();
        for (String key : keys) {
            String value = headers.getString(key);
            request.addHeader(key, value);
        }

        // 确保有Content-Type
        if (!request.containsHeader("Content-Type") &&
                request instanceof HttpEntityEnclosingRequestBase) {
            request.addHeader("Content-Type", "application/json; charset=utf-8");
        }
    }

    /**
     * 执行请求并处理响应
     */
    private static String executeRequest(HttpRequestBase request) {
//        logger.info("发送 {} 请求到: {}", request.getMethod(), request.getURI());

        try (CloseableHttpResponse response = httpClient.execute(request)) {
            // 获取状态码
            int statusCode = response.getStatusLine().getStatusCode();

            // 获取响应实体
            HttpEntity entity = response.getEntity();
            if (entity == null) {
//                logger.warn("空响应体 [{}]", statusCode);
                return "";
            }

            // 读取响应内容
            String responseBody = EntityUtils.toString(entity, StandardCharsets.UTF_8);

            // 记录响应日志
            logResponse(request, responseBody, statusCode);

            // 检查状态码
            if (statusCode >= 400) {
//                logger.error("请求失败: HTTP {}", statusCode);
                throw new HttpRequestException(statusCode, "HTTP " + statusCode, responseBody);
            }

            return responseBody;
        } catch (IOException e) {
//            logger.error("请求执行失败: {}", e.getMessage());
            throw new HttpRequestException(500, "请求执行失败: " + e.getMessage(), null);
        } finally {
            request.releaseConnection(); // 确保释放连接
        }
    }

    /**
     * 记录响应日志
     */
    private static void logResponse(HttpRequestBase request, String responseBody, int statusCode) {
        String method = request.getMethod();
        String url = request.getURI().toString();

        // 截断过长的响应体
        String logBody = responseBody;
        if (responseBody != null && responseBody.length() > 500) {
            logBody = responseBody.substring(0, 500) + "...[截断 " + (responseBody.length() - 500) + "字符]";
        }

//        logger.info("{} {} => {}\n响应: {}", method, url, statusCode, logBody);
    }

    /**
     * 自定义DELETE请求类（支持请求体）
     */
    private static class HttpDeleteWithBody extends HttpEntityEnclosingRequestBase {
        public HttpDeleteWithBody(final String uri) {
            super();
            setURI(java.net.URI.create(uri));
        }

        @Override
        public String getMethod() {
            return "DELETE";
        }
    }

    /**
     * 自定义HTTP请求异常
     */
    public static class HttpRequestException extends RuntimeException {
        private final int statusCode;
        private final String responseBody;

        public HttpRequestException(int statusCode, String message, String responseBody) {
            super(message);
            this.statusCode = statusCode;
            this.responseBody = responseBody;
        }

        public int getStatusCode() {
            return statusCode;
        }

        public String getResponseBody() {
            return responseBody;
        }
    }
}
